package api

import (
	"getaway/basic/config"
	__ "getaway/basic/proto/orderproto"
	"getaway/handler/request"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"net/http"
	"os"
	"path/filepath"
)

// DownloadExportFile 处理导出文件下载请求
func DownloadExportFile(c *gin.Context) {
	// 1. 记录请求信息用于调试
	zap.L().Info("收到下载导出文件请求",
		zap.String("path", c.Request.URL.Path),
		zap.String("method", c.Request.Method),
		zap.String("clientIP", c.ClientIP()))

	// 检查是否有JWT令牌
	token := c.Request.Header.Get("x-token")
	if token == "" {
		zap.L().Error("下载导出文件请求缺少x-token")
		c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "msg": "未提供认证令牌"})
		return
	}

	// 2. 绑定并验证参数
	var req request.DownloadExportFileReq
	if err := c.ShouldBind(&req); err != nil {
		zap.L().Error("下载导出文件请求参数无效", zap.Any("error", err), zap.Any("request", req))
		c.JSON(http.StatusBadRequest, gin.H{"code": 1, "msg": "参数无效: " + err.Error()})
		return
	}

	// 检查用户ID是否从JWT中提取成功
	userId, exists := c.Get("userId")
	if !exists {
		zap.L().Error("无法从JWT中提取用户ID")
		c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "msg": "认证失败，无法获取用户ID"})
		return
	}

	zap.L().Info("下载请求参数验证通过",
		zap.Any("userId", userId),
		zap.String("taskId", req.TaskId))

	// 3. 调用order_srv服务获取任务状态
	resp, err := config.OrderClient.GetExportTaskStatus(c, &__.GetExportTaskStatusReq{
		TaskId: req.TaskId,
		UserId: uint32(c.GetUint("userId")),
	})

	if err != nil {
		zap.L().Error("调用GetExportTaskStatus失败", zap.Error(err), zap.String("taskId", req.TaskId))
		// 解析gRPC错误码
		if st, ok := status.FromError(err); ok {
			switch st.Code() {
			case codes.NotFound:
				c.JSON(http.StatusNotFound, gin.H{"code": 1, "msg": "任务不存在"})
				return
			case codes.Unauthenticated, codes.PermissionDenied:
				c.JSON(http.StatusForbidden, gin.H{"code": 1, "msg": "无权限访问"})
				return
			default:
				c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "系统内部错误: " + st.Message()})
				return
			}
		}
		c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "系统内部错误: " + err.Error()})
		return
	}

	// 4. 验证任务状态和文件路径
	if resp.Status != 2 { // 状态2表示完成
		zap.L().Error("任务未完成", zap.Int32("status", int32(resp.Status)), zap.String("taskId", req.TaskId))
		c.JSON(http.StatusBadRequest, gin.H{"code": 1, "msg": "任务尚未完成，请稍后再试"})
		return
	}

	if resp.FilePath == "" || resp.FilePath == "error" {
		zap.L().Error("导出任务已完成但文件路径为空", zap.String("taskId", req.TaskId))
		c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "导出文件不存在"})
		return
	}

	// 5. 检查文件是否存在
	_, err = os.Stat(resp.FilePath)
	if os.IsNotExist(err) {
		zap.L().Error("导出文件不存在于文件系统", zap.String("filePath", resp.FilePath), zap.String("taskId", req.TaskId))
		c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "导出文件不存在"})
		return
	}

	// 6. 获取文件名用于下载
	fileName := filepath.Base(resp.FilePath)
	// 确保文件名安全（避免路径遍历攻击）
	safeFileName := filepath.Base(fileName)

	// 7. 设置响应头，触发文件下载
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", "attachment; filename=\""+safeFileName+"\"")
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Expires", "0")
	c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
	c.Header("Pragma", "no-cache")
	// 添加安全相关头部
	c.Header("Content-Security-Policy", "default-src 'self'")
	c.Header("X-Content-Type-Options", "nosniff")
	c.Header("X-Frame-Options", "DENY")
	c.Header("X-XSS-Protection", "1; mode=block")

	// 8. 记录文件下载日志
	zap.L().Info("用户下载导出文件",
		zap.Uint("userId", c.GetUint("userId")),
		zap.String("taskId", req.TaskId),
		zap.String("fileName", safeFileName),
		zap.String("filePath", resp.FilePath))
	// 9. 提供文件下载服务
	// 注意：在实际项目中，应该使用文件服务器或CDN来提供大文件下载
	c.File(resp.FilePath)
	zap.L().Info("文件下载请求处理完成", zap.String("taskId", req.TaskId))
}
